home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -screenplay- / shareware / warpquake / warpquakesrc / cmd.c < prev    next >
C/C++ Source or Header  |  2000-02-29  |  13KB  |  706 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // cmd.c -- Quake script command processing module
  21.  
  22. #include "quakedef.h"
  23.  
  24. void Cmd_ForwardToServer (void);
  25.  
  26. #define    MAX_ALIAS_NAME    32
  27.  
  28. typedef struct cmdalias_s
  29. {
  30.     struct cmdalias_s    *next;
  31.     char    name[MAX_ALIAS_NAME];
  32.     char    *value;
  33. } cmdalias_t;
  34.  
  35. cmdalias_t    *cmd_alias;
  36.  
  37. int trashtest;
  38. int *trashspot;
  39.  
  40. qboolean    cmd_wait;
  41.  
  42. //=============================================================================
  43.  
  44. /*
  45. ============
  46. Cmd_Wait_f
  47.  
  48. Causes execution of the remainder of the command buffer to be delayed until
  49. next frame.  This allows commands like:
  50. bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
  51. ============
  52. */
  53. void Cmd_Wait_f (void)
  54. {
  55.     cmd_wait = true;
  56. }
  57.  
  58. /*
  59. =============================================================================
  60.  
  61.                         COMMAND BUFFER
  62.  
  63. =============================================================================
  64. */
  65.  
  66. sizebuf_t    cmd_text;
  67.  
  68. /*
  69. ============
  70. Cbuf_Init
  71. ============
  72. */
  73. void Cbuf_Init (void)
  74. {
  75.     SZ_Alloc (&cmd_text, 8192);        // space for commands and script files
  76. }
  77.  
  78.  
  79. /*
  80. ============
  81. Cbuf_AddText
  82.  
  83. Adds command text at the end of the buffer
  84. ============
  85. */
  86. void Cbuf_AddText (char *text)
  87. {
  88.     int        l;
  89.     
  90.     l = Q_strlen (text);
  91.  
  92.     if (cmd_text.cursize + l >= cmd_text.maxsize)
  93.     {
  94.         Con_Printf ("Cbuf_AddText: overflow\n");
  95.         return;
  96.     }
  97.  
  98.     SZ_Write (&cmd_text, text, Q_strlen (text));
  99. }
  100.  
  101.  
  102. /*
  103. ============
  104. Cbuf_InsertText
  105.  
  106. Adds command text immediately after the current command
  107. Adds a \n to the text
  108. FIXME: actually change the command buffer to do less copying
  109. ============
  110. */
  111. void Cbuf_InsertText (char *text)
  112. {
  113.     char    *temp;
  114.     int        templen;
  115.  
  116. // copy off any commands still remaining in the exec buffer
  117.     templen = cmd_text.cursize;
  118.     if (templen)
  119.     {
  120.         temp = Z_Malloc (templen);
  121.         Q_memcpy (temp, cmd_text.data, templen);
  122.         SZ_Clear (&cmd_text);
  123.     }
  124.     else
  125.         temp = NULL;    // shut up compiler
  126.         
  127. // add the entire text of the file
  128.     Cbuf_AddText (text);
  129.     
  130. // add the copied off data
  131.     if (templen)
  132.     {
  133.         SZ_Write (&cmd_text, temp, templen);
  134.         Z_Free (temp);
  135.     }
  136. }
  137.  
  138. /*
  139. ============
  140. Cbuf_Execute
  141. ============
  142. */
  143. void Cbuf_Execute (void)
  144. {
  145.     int        i;
  146.     char    *text;
  147.     char    line[1024];
  148.     int        quotes;
  149.     
  150.     while (cmd_text.cursize)
  151.     {
  152. // find a \n or ; line break
  153.         text = (char *)cmd_text.data;
  154.  
  155.         quotes = 0;
  156.         for (i=0 ; i< cmd_text.cursize ; i++)
  157.         {
  158.             if (text[i] == '"')
  159.                 quotes++;
  160.             if ( !(quotes&1) &&  text[i] == ';')
  161.                 break;    // don't break if inside a quoted string
  162.             if (text[i] == '\n')
  163.                 break;
  164.         }
  165.             
  166.                 
  167.         memcpy (line, text, i);
  168.         line[i] = 0;
  169.         
  170. // delete the text from the command buffer and move remaining commands down
  171. // this is necessary because commands (exec, alias) can insert data at the
  172. // beginning of the text buffer
  173.  
  174.         if (i == cmd_text.cursize)
  175.             cmd_text.cursize = 0;
  176.         else
  177.         {
  178.             i++;
  179.             cmd_text.cursize -= i;
  180.             Q_memcpy (text, text+i, cmd_text.cursize);
  181.         }
  182.  
  183. // execute the command line
  184.         Cmd_ExecuteString (line, src_command);
  185.         
  186.         if (cmd_wait)
  187.         {    // skip out while text still remains in buffer, leaving it
  188.             // for next frame
  189.             cmd_wait = false;
  190.             break;
  191.         }
  192.     }
  193. }
  194.  
  195. /*
  196. ==============================================================================
  197.  
  198.                         SCRIPT COMMANDS
  199.  
  200. ==============================================================================
  201. */
  202.  
  203. /*
  204. ===============
  205. Cmd_StuffCmds_f
  206.  
  207. Adds command line parameters as script statements
  208. Commands lead with a +, and continue until a - or another +
  209. quake +prog jctest.qp +cmd amlev1
  210. quake -nosound +cmd amlev1
  211. ===============
  212. */
  213. void Cmd_StuffCmds_f (void)
  214. {
  215.     int        i, j;
  216.     int        s;
  217.     char    *text, *build, c;
  218.         
  219.     if (Cmd_Argc () != 1)
  220.     {
  221.         Con_Printf ("stuffcmds : execute command line parameters\n");
  222.         return;
  223.     }
  224.  
  225. // build the combined string to parse from
  226.     s = 0;
  227.     for (i=1 ; i<com_argc ; i++)
  228.     {
  229.         if (!com_argv[i])
  230.             continue;        // NEXTSTEP nulls out -NXHost
  231.         s += Q_strlen (com_argv[i]) + 1;
  232.     }
  233.     if (!s)
  234.         return;
  235.         
  236.     text = Z_Malloc (s+1);
  237.     text[0] = 0;
  238.     for (i=1 ; i<com_argc ; i++)
  239.     {
  240.         if (!com_argv[i])
  241.             continue;        // NEXTSTEP nulls out -NXHost
  242.         Q_strcat (text,com_argv[i]);
  243.         if (i != com_argc-1)
  244.             Q_strcat (text, " ");
  245.     }
  246.     
  247. // pull out the commands
  248.     build = Z_Malloc (s+1);
  249.     build[0] = 0;
  250.     
  251.     for (i=0 ; i<s-1 ; i++)
  252.     {
  253.         if (text[i] == '+')
  254.         {
  255.             i++;
  256.  
  257.             for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
  258.                 ;
  259.  
  260.             c = text[j];
  261.             text[j] = 0;
  262.             
  263.             Q_strcat (build, text+i);
  264.             Q_strcat (build, "\n");
  265.             text[j] = c;
  266.             i = j-1;
  267.         }
  268.     }
  269.     
  270.     if (build[0])
  271.         Cbuf_InsertText (build);
  272.     
  273.     Z_Free (text);
  274.     Z_Free (build);
  275. }
  276.  
  277.  
  278. /*
  279. ===============
  280. Cmd_Exec_f
  281. ===============
  282. */
  283. void Cmd_Exec_f (void)
  284. {
  285.     char    *f;
  286.     int        mark;
  287.  
  288.     if (Cmd_Argc () != 2)
  289.     {
  290.         Con_Printf ("exec <filename> : execute a script file\n");
  291.         return;
  292.     }
  293.  
  294.     mark = Hunk_LowMark ();
  295.     f = (char *)COM_LoadHunkFile (Cmd_Argv(1));
  296.     if (!f)
  297.     {
  298.         Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
  299.         return;
  300.     }
  301.     Con_Printf ("execing %s\n",Cmd_Argv(1));
  302.     
  303.     Cbuf_InsertText (f);
  304.     Hunk_FreeToLowMark (mark);
  305. }
  306.  
  307.  
  308. /*
  309. ===============
  310. Cmd_Echo_f
  311.  
  312. Just prints the rest of the line to the console
  313. ===============
  314. */
  315. void Cmd_Echo_f (void)
  316. {
  317.     int        i;
  318.     
  319.     for (i=1 ; i<Cmd_Argc() ; i++)
  320.         Con_Printf ("%s ",Cmd_Argv(i));
  321.     Con_Printf ("\n");
  322. }
  323.  
  324. /*
  325. ===============
  326. Cmd_Alias_f
  327.  
  328. Creates a new command that executes a command string (possibly ; seperated)
  329. ===============
  330. */
  331.  
  332. char *CopyString (char *in)
  333. {
  334.     char    *out;
  335.     
  336.     out = Z_Malloc (strlen(in)+1);
  337.     strcpy (out, in);
  338.     return out;
  339. }
  340.  
  341. void Cmd_Alias_f (void)
  342. {
  343.     cmdalias_t    *a;
  344.     char        cmd[1024];
  345.     int            i, c;
  346.     char        *s;
  347.  
  348.     if (Cmd_Argc() == 1)
  349.     {
  350.         Con_Printf ("Current alias commands:\n");
  351.         for (a = cmd_alias ; a ; a=a->next)
  352.             Con_Printf ("%s : %s\n", a->name, a->value);
  353.         return;
  354.     }
  355.  
  356.     s = Cmd_Argv(1);
  357.     if (strlen(s) >= MAX_ALIAS_NAME)
  358.     {
  359.         Con_Printf ("Alias name is too long\n");
  360.         return;
  361.     }
  362.  
  363.     // if the alias allready exists, reuse it
  364.     for (a = cmd_alias ; a ; a=a->next)
  365.     {
  366.         if (!strcmp(s, a->name))
  367.         {
  368.             Z_Free (a->value);
  369.             break;
  370.         }
  371.     }
  372.  
  373.     if (!a)
  374.     {
  375.         a = Z_Malloc (sizeof(cmdalias_t));
  376.         a->next = cmd_alias;
  377.         cmd_alias = a;
  378.     }
  379.     strcpy (a->name, s);    
  380.  
  381. // copy the rest of the command line
  382.     cmd[0] = 0;        // start out with a null string
  383.     c = Cmd_Argc();
  384.     for (i=2 ; i< c ; i++)
  385.     {
  386.         strcat (cmd, Cmd_Argv(i));
  387.         if (i != c)
  388.             strcat (cmd, " ");
  389.     }
  390.     strcat (cmd, "\n");
  391.     
  392.     a->value = CopyString (cmd);
  393. }
  394.  
  395. /*
  396. =============================================================================
  397.  
  398.                     COMMAND EXECUTION
  399.  
  400. =============================================================================
  401. */
  402.  
  403. typedef struct cmd_function_s
  404. {
  405.     struct cmd_function_s    *next;
  406.     char                    *name;
  407.     xcommand_t                function;
  408. } cmd_function_t;
  409.  
  410.  
  411. #define    MAX_ARGS        80
  412.  
  413. static    int            cmd_argc;
  414. static    char        *cmd_argv[MAX_ARGS];
  415. static    char        *cmd_null_string = "";
  416. static    char        *cmd_args = NULL;
  417.  
  418. cmd_source_t    cmd_source;
  419.  
  420.  
  421. static    cmd_function_t    *cmd_functions;        // possible commands to execute
  422.  
  423. /*
  424. ============
  425. Cmd_Init
  426. ============
  427. */
  428. void Cmd_Init (void)
  429. {
  430. //
  431. // register our commands
  432. //
  433.     Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
  434.     Cmd_AddCommand ("exec",Cmd_Exec_f);
  435.     Cmd_AddCommand ("echo",Cmd_Echo_f);
  436.     Cmd_AddCommand ("alias",Cmd_Alias_f);
  437.     Cmd_AddCommand ("cmd", Cmd_ForwardToServer);
  438.     Cmd_AddCommand ("wait", Cmd_Wait_f);
  439. }
  440.  
  441. /*
  442. ============
  443. Cmd_Argc
  444. ============
  445. */
  446. int        Cmd_Argc (void)
  447. {
  448.     return cmd_argc;
  449. }
  450.  
  451. /*
  452. ============
  453. Cmd_Argv
  454. ============
  455. */
  456. char    *Cmd_Argv (int arg)
  457. {
  458.     if ( (unsigned)arg >= cmd_argc )
  459.         return cmd_null_string;
  460.     return cmd_argv[arg];    
  461. }
  462.  
  463. /*
  464. ============
  465. Cmd_Args
  466. ============
  467. */
  468. char        *Cmd_Args (void)
  469. {
  470.     return cmd_args;
  471. }
  472.  
  473.  
  474. /*
  475. ============
  476. Cmd_TokenizeString
  477.  
  478. Parses the given string into command line tokens.
  479. ============
  480. */
  481. void Cmd_TokenizeString (char *text)
  482. {
  483.     int        i;
  484.     
  485. // clear the args from the last string
  486.     for (i=0 ; i<cmd_argc ; i++)
  487.         Z_Free (cmd_argv[i]);
  488.         
  489.     cmd_argc = 0;
  490.     cmd_args = NULL;
  491.     
  492.     while (1)
  493.     {
  494. // skip whitespace up to a /n
  495.         while (*text && *text <= ' ' && *text != '\n')
  496.         {
  497.             text++;
  498.         }
  499.         
  500.         if (*text == '\n')
  501.         {    // a newline seperates commands in the buffer
  502.             text++;
  503.             break;
  504.         }
  505.  
  506.         if (!*text)
  507.             return;
  508.     
  509.         if (cmd_argc == 1)
  510.              cmd_args = text;
  511.             
  512.         text = COM_Parse (text);
  513.         if (!text)
  514.             return;
  515.  
  516.         if (cmd_argc < MAX_ARGS)
  517.         {
  518.             cmd_argv[cmd_argc] = Z_Malloc (Q_strlen(com_token)+1);
  519.             Q_strcpy (cmd_argv[cmd_argc], com_token);
  520.             cmd_argc++;
  521.         }
  522.     }
  523.     
  524. }
  525.  
  526.  
  527. /*
  528. ============
  529. Cmd_AddCommand
  530. ============
  531. */
  532. void    Cmd_AddCommand (char *cmd_name, xcommand_t function)
  533. {
  534.     cmd_function_t    *cmd;
  535.     
  536.     if (host_initialized)    // because hunk allocation would get stomped
  537.         Sys_Error ("Cmd_AddCommand after host_initialized");
  538.         
  539. // fail if the command is a variable name
  540.     if (Cvar_VariableString(cmd_name)[0])
  541.     {
  542.         Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
  543.         return;
  544.     }
  545.     
  546. // fail if the command already exists
  547.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  548.     {
  549.         if (!Q_strcmp (cmd_name, cmd->name))
  550.         {
  551.             Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
  552.             return;
  553.         }
  554.     }
  555.  
  556.     cmd = Hunk_Alloc (sizeof(cmd_function_t));
  557.     cmd->name = cmd_name;
  558.     cmd->function = function;
  559.     cmd->next = cmd_functions;
  560.     cmd_functions = cmd;
  561. }
  562.  
  563. /*
  564. ============
  565. Cmd_Exists
  566. ============
  567. */
  568. qboolean    Cmd_Exists (char *cmd_name)
  569. {
  570.     cmd_function_t    *cmd;
  571.  
  572.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  573.     {
  574.         if (!Q_strcmp (cmd_name,cmd->name))
  575.             return true;
  576.     }
  577.  
  578.     return false;
  579. }
  580.  
  581.  
  582.  
  583. /*
  584. ============
  585. Cmd_CompleteCommand
  586. ============
  587. */
  588. char *Cmd_CompleteCommand (char *partial)
  589. {
  590.     cmd_function_t    *cmd;
  591.     int                len;
  592.     
  593.     len = Q_strlen(partial);
  594.     
  595.     if (!len)
  596.         return NULL;
  597.         
  598. // check functions
  599.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  600.         if (!Q_strncmp (partial,cmd->name, len))
  601.             return cmd->name;
  602.  
  603.     return NULL;
  604. }
  605.  
  606. /*
  607. ============
  608. Cmd_ExecuteString
  609.  
  610. A complete command line has been parsed, so try to execute it
  611. FIXME: lookupnoadd the token to speed search?
  612. ============
  613. */
  614. void    Cmd_ExecuteString (char *text, cmd_source_t src)
  615. {    
  616.     cmd_function_t    *cmd;
  617.     cmdalias_t        *a;
  618.  
  619.     cmd_source = src;
  620.     Cmd_TokenizeString (text);
  621.             
  622. // execute the command line
  623.     if (!Cmd_Argc())
  624.         return;        // no tokens
  625.  
  626. // check functions
  627.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  628.     {
  629.         if (!Q_strcasecmp (cmd_argv[0],cmd->name))
  630.         {
  631.             cmd->function ();
  632.             return;
  633.         }
  634.     }
  635.  
  636. // check alias
  637.     for (a=cmd_alias ; a ; a=a->next)
  638.     {
  639.         if (!Q_strcasecmp (cmd_argv[0], a->name))
  640.         {
  641.             Cbuf_InsertText (a->value);
  642.             return;
  643.         }
  644.     }
  645.     
  646. // check cvars
  647.     if (!Cvar_Command ())
  648.         Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
  649.     
  650. }
  651.  
  652.  
  653. /*
  654. ===================
  655. Cmd_ForwardToServer
  656.  
  657. Sends the entire command line over to the server
  658. ===================
  659. */
  660. void Cmd_ForwardToServer (void)
  661. {
  662.     if (cls.state != ca_connected)
  663.     {
  664.         Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
  665.         return;
  666.     }
  667.     
  668.     if (cls.demoplayback)
  669.         return;        // not really connected
  670.  
  671.     MSG_WriteByte (&cls.message, clc_stringcmd);
  672.     if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0)
  673.     {
  674.         SZ_Print (&cls.message, Cmd_Argv(0));
  675.         SZ_Print (&cls.message, " ");
  676.     }
  677.     if (Cmd_Argc() > 1)
  678.         SZ_Print (&cls.message, Cmd_Args());
  679.     else
  680.         SZ_Print (&cls.message, "\n");
  681. }
  682.  
  683.  
  684. /*
  685. ================
  686. Cmd_CheckParm
  687.  
  688. Returns the position (1 to argc-1) in the command's argument list
  689. where the given parameter apears, or 0 if not present
  690. ================
  691. */
  692.  
  693. int Cmd_CheckParm (char *parm)
  694. {
  695.     int i;
  696.     
  697.     if (!parm)
  698.         Sys_Error ("Cmd_CheckParm: NULL");
  699.  
  700.     for (i = 1; i < Cmd_Argc (); i++)
  701.         if (! Q_strcasecmp (parm, Cmd_Argv (i)))
  702.             return i;
  703.             
  704.     return 0;
  705. }
  706.